/* Copyright 2010 by Matt Van Der Westhuizen */

package org.chaoticengine.ast.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.chaoticengine.ast.pattern.Model;
import org.newdawn.slick.geom.Vector2f;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

/**
 * High-level abstract model of a location on the world map.
 *
 * @author Matt Van Der Westhuizen <mattpwest@gmail.com>
 */
@Root(name="location")
public class Location extends Model implements HasTurn, ShipLocation {
    protected String name = "";

    @Element(name="x")
    protected int x = 0;

    @Element(name="y")
    protected int y = 0;

    @Element(name="altitude")
    protected Altitude altitude = Altitude.GROUND;

    @Element(name="population")
    protected Integer population = 0;

    @Element(name="gold")
    protected Integer gold = 0;

    //@Element(name="goods", required=false)
    protected TradeInventory goods = null;

    //@ElementMap(entry="production", key="TradeGood", value="Quantity", inline=true, keyType=TradeGood.class)
    protected HashMap<TradeGood, Float> production = null;

    //@ElementMap(entry="consumption", key="TradeGood", value="Quantity", inline=true, keyType=TradeGood.class)
    protected HashMap<TradeGood, Float> consumption = null;

    protected List<AirShip> ships = null;

    public Location() {
        super();

        ships = new ArrayList<AirShip>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getX() {
        return(x);
    }

    public void setX(int x) {
        this.x = x;
        this.refreshObservers();
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
        this.refreshObservers();
    }

    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;
        this.refreshObservers();
    }

    public Vector2f getPosition() {
        return(new Vector2f(x, y));
    }

    public Altitude getAltitude() {
        return(altitude);
    }

    public void setAltitude(Altitude alt) {
        this.altitude = alt;
        this.refreshObservers();
    }

    public Integer getPopulation() {
        return population;
    }

    public void setPopulation(Integer population) {
        this.population = population;
    }

    public Integer getGold() {
        return gold;
    }

    public void setGold(Integer gold) {
        this.gold = gold;
    }

    public TradeInventory getGoods() {
        return goods;
    }

    public void setGoods(TradeInventory goods) {
        this.goods = goods;
    }

    public HashMap<TradeGood, Float> getProduction() {
        return production;
    }

    public void setProduction(HashMap<TradeGood, Float> production) {
        this.production = production;

        checkInventory(production.keySet().iterator());
    }

    public Float getProduction(TradeGood good) {
        if (production.containsKey(good)) {
            return(production.get(good));
        } else {
            return(0.0f);
        }
    }

    public HashMap<TradeGood, Float> getConsumption() {
        return consumption;
    }

    public void setConsumption(HashMap<TradeGood, Float> consumption) {
        this.consumption = consumption;

        checkInventory(consumption.keySet().iterator());
    }

    public Float getConsumption(TradeGood good) {
        if (consumption.containsKey(good)) {
            return(consumption.get(good));
        } else {
            return(0.0f);
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Location clone = new Location();
        clone.setPosition(x, y);
        clone.setAltitude(altitude);
        clone.setPopulation(population);
        clone.setName(name);
        return(clone);
    }

    public Location copy() {
        Location copy = null;
        try {
            copy = (Location) this.clone();
        } catch (CloneNotSupportedException cnsEx) {
            System.out.println("Error: Failed to clone Location " + this.toString() + "!");
        }
        return(copy);
    }

    public void takeTurn(float hours) {
    }

    /**
     * Ensures that all the TradeGoods returned by iterator <b>it</b>, are present
     * in the TradeInventory - this is used to ensure that Locations can trade in
     * at least the goods they produce and consume.
     * 
     * @param it Iterator that returns a list of TradeGoods.
     */
    private void checkInventory(Iterator<TradeGood> it) {
        if (goods == null) {
            goods = new TradeInventory();
        }
        HashMap<TradeGood, Float> inv = goods.getInventory();

        while (it.hasNext()) {
            TradeGood t = it.next();

            if (!inv.containsKey(t)) {
                inv.put(t, 0.0f);
            }
        }
        
        goods.setInventory(inv);
    }

    public void addShip(AirShip ship) {
        ships.add(ship);
        ship.setLocation(this);
        ship.setAltitude(altitude);
        this.refreshObservers();
    }

    public void clearShips() {
        ships.clear();
    }

    public List<AirShip> getShips() {
        return(ships);
    }

    public void removeShip(AirShip ship) {
        ships.remove(ship);
    }

    public void setShips(List<AirShip> ships) {
        this.ships = ships;

        Iterator<AirShip> shipIt = ships.iterator();
        while (shipIt.hasNext()) {
            AirShip ship = shipIt.next();
            ship.setLocation(this);
            ship.setAltitude(altitude);
            this.refreshObservers();
        }
    }
}
